/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.activity;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.gef.palette.MarqueeToolEntry;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteDrawer;
import org.eclipse.gef.palette.PaletteEntry;
import org.eclipse.gef.palette.PaletteGroup;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PaletteSeparator;
import org.eclipse.gef.palette.PaletteStack;
import org.eclipse.gef.palette.PanningSelectionToolEntry;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.ui.palette.FlyoutPaletteComposite.FlyoutPreferences;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.uml2.uml.AcceptCallAction;
import org.eclipse.uml2.uml.AcceptEventAction;
import org.eclipse.uml2.uml.ActionInputPin;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.ActivityFinalNode;
import org.eclipse.uml2.uml.ActivityParameterNode;
import org.eclipse.uml2.uml.AddStructuralFeatureValueAction;
import org.eclipse.uml2.uml.AddVariableValueAction;
import org.eclipse.uml2.uml.BroadcastSignalAction;
import org.eclipse.uml2.uml.CallBehaviorAction;
import org.eclipse.uml2.uml.CallOperationAction;
import org.eclipse.uml2.uml.CentralBufferNode;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.ControlFlow;
import org.eclipse.uml2.uml.CreateObjectAction;
import org.eclipse.uml2.uml.DataStoreNode;
import org.eclipse.uml2.uml.DecisionNode;
import org.eclipse.uml2.uml.DestroyObjectAction;
import org.eclipse.uml2.uml.FlowFinalNode;
import org.eclipse.uml2.uml.ForkNode;
import org.eclipse.uml2.uml.InitialNode;
import org.eclipse.uml2.uml.InputPin;
import org.eclipse.uml2.uml.JoinNode;
import org.eclipse.uml2.uml.MergeNode;
import org.eclipse.uml2.uml.ObjectFlow;
import org.eclipse.uml2.uml.OpaqueAction;
import org.eclipse.uml2.uml.OutputPin;
import org.eclipse.uml2.uml.ReadExtentAction;
import org.eclipse.uml2.uml.SendObjectAction;
import org.eclipse.uml2.uml.SendSignalAction;
import org.eclipse.uml2.uml.TestIdentityAction;
import org.eclipse.uml2.uml.UnmarshallAction;
import org.eclipse.uml2.uml.ValueSpecificationAction;

import com.cea.papyrus.core.IPapyrusUIConstants;
import com.cea.papyrus.core.PapyrusMessages;
import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.editor.CreationEntryFactory;
import com.cea.papyrus.core.editor.DiagramPalette;
import com.cea.papyrus.core.pseudoelement.GraphicalLink;
import com.cea.papyrus.core.ui.dialogs.PapyrusMessageDialog;


/**
 * Manages creation of the palette in the activity diagram editor.
 * 
 * @author Gilles Cannenterre
 * @author Sylvain Robert
 * @since 20 feb. 07
 */
public class ActivityDiagramPaletteFactory extends CreationEntryFactory {

	/**
	 * The Constant PALETTE_DOCK_LOCATION.
	 */
	private static final String PALETTE_DOCK_LOCATION = "ShapesEditorPaletteFactory.Location";

	/**
	 * The Constant PALETTE_SIZE.
	 */
	private static final String PALETTE_SIZE = "ShapesEditorPaletteFactory.Size";

	/**
	 * The Constant PALETTE_STATE.
	 */
	private static final String PALETTE_STATE = "ShapesEditorPaletteFactory.State";

	/**
	 * Creates the shapes drawer.
	 * 
	 * @return the palette container
	 */
	private static PaletteContainer createShapesDrawer() {
		PaletteDrawer componentsDrawer = new PaletteDrawer("Uml Element");

		// Begin of entry stack for Acitivty diagrams elements		
		List<PaletteEntry> entries = new ArrayList<PaletteEntry>();
		try {
			PaletteStack paletteStack = null;
			
			// Activity creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddActivityCommand_Label,
							PapyrusMessages.AddActivityCommand_Description,
							Activity.class, null));
			
			// Creation of a palette stack for actions
			paletteStack = new PaletteStack("", "", null);
			// AcceptCallAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddAcceptCallActionCommand_Label,
							PapyrusMessages.AddAcceptCallActionCommand_Description,
							AcceptCallAction.class, null));

			// AcceptEventAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddAcceptEventActionCommand_Label,
							PapyrusMessages.AddAcceptEventActionCommand_Description,
							AcceptEventAction.class, null));
			
			// AddStructuralFeatureValueAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddStructuralFeatureValueActionCommand_Label,
							PapyrusMessages.AddStructuralFeatureValueActionCommand_Description,
							AddStructuralFeatureValueAction.class, null));
			// AddVariableValueAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddAddVariableValueActionCommand_Label,
							PapyrusMessages.AddAddVariableValueActionCommand_Description,
							AddVariableValueAction.class, null));
			//BroacastSignalAction
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddBroadcastSignalActionCommand_Label,
							PapyrusMessages.AddBroadcastSignalActionCommand_Description,
							BroadcastSignalAction.class, null));
			
			// CallBehaviourAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddCallBehaviorActionCommand_Label,
							PapyrusMessages.AddCallBehaviorActionCommand_Description,
							CallBehaviorAction.class, null));
			
			// CallOperationAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddCallOperationActionCommand_Label,
							PapyrusMessages.AddCallOperationActionCommand_Description,
							CallOperationAction.class, null));
			// CreateObjectAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddCreateObjectActionCommand_Label,
							PapyrusMessages.AddCreateObjectActionCommand_Description,
							CreateObjectAction.class, null));
			// DestroyObjectAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddDestroyObjectActionCommand_Label,
							PapyrusMessages.AddDestroyObjectActionCommand_Description,
							DestroyObjectAction.class, null));
			// OpaqueAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddOpaqueActionCommand_Label,
							PapyrusMessages.AddOpaqueActionCommand_Description,
							OpaqueAction.class, null));
			// ReadExtentAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.ReadExtentActionCommand_Label,
							PapyrusMessages.ReadExtentActionCommand_Description,
							ReadExtentAction.class, null));
			
			// SendObjectAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddSendObjectActionCommand_Label,
							PapyrusMessages.AddSendObjectActionCommand_Description,
							SendObjectAction.class, null));
			
			// SendSignalAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddSendSignalActionCommand_Label,
							PapyrusMessages.AddSendSignalActionCommand_Description,
							SendSignalAction.class, null));
			//BroacastSignalAction
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddTestIdentityActionCommand_Label,
							PapyrusMessages.AddTestIdentityActionCommand_Description,
							TestIdentityAction.class, null));
			
			// UnmarshallAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddUnmarshallActionCommand_Label,
							PapyrusMessages.AddUnmarshallActionCommand_Description,
							UnmarshallAction.class, null));
			
			// ValueSpecificationAction creation tool
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddValueSpecificationActionCommand_Label,
							PapyrusMessages.AddValueSpecificationActionCommand_Description,
							ValueSpecificationAction.class, null));
			
			entries.add(paletteStack);
			// End of actions palette stack

			// Creation of a palette stack for object nodes
			paletteStack = new PaletteStack("", "", null);
			// CentralBufferNode creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddCentralBufferNodeCommand_Label,
							PapyrusMessages.AddCentralBufferNodeCommand_Description,
							CentralBufferNode.class, null));
			
			// DataStoreNode creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddDataStoreNodeCommand_Label,
							PapyrusMessages.AddDataStoreNodeCommand_Description,
							DataStoreNode.class, null));
			
			entries.add(paletteStack);
			// End of object nodes palette stack
			
			//	ActivityParameterNode
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddActivityParameterNodeCommand_Label,
							PapyrusMessages.AddActivityParameterNodeCommand_Description,
							ActivityParameterNode.class, null));
			
			//	Creation of a palette stack for Pins
			paletteStack = new PaletteStack("", "", null);
			// InputPin creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddInputPinCommand_Label,
							PapyrusMessages.AddInputPinCommand_Description,
							InputPin.class, null));
			
			// ActionInputPin creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddActionInputPinCommand_Label,
							PapyrusMessages.AddActionInputPinCommand_Description,
							ActionInputPin.class, null));
			
			entries.add(paletteStack);
			// End of actions palette stack
			
			// OutputPin creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddOutputPinCommand_Label,
							PapyrusMessages.AddOutputPinCommand_Description,
							OutputPin.class, null));
			
			// Creation of a palette stack for control nodes
			paletteStack = new PaletteStack("", "", null);
			// Decision Node creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddDecisionNodeCommand_Label,
							PapyrusMessages.AddDecisionNodeCommand_Description,
							DecisionNode.class, null));
			
			// Activity Final Node creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddActivityFinalNodeCommand_Label,
							PapyrusMessages.AddActivityFinalNodeCommand_Description,
							ActivityFinalNode.class, null));
			
			// Flow Final Node creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddFlowFinalNodeCommand_Label,
							PapyrusMessages.AddFlowFinalNodeCommand_Description,
							FlowFinalNode.class, null));
			
			// InitialNode creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddInitialNodeCommand_Label,
							PapyrusMessages.AddInitialNodeCommand_Description,
							InitialNode.class, null));
			
			// ForkNode creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddForkNodeCommand_Label,
							PapyrusMessages.AddForkNodeCommand_Description,
							ForkNode.class, null));

			
//			 JoinNode creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddJoinNodeCommand_Label,
							PapyrusMessages.AddJoinNodeCommand_Description,
							JoinNode.class, null));
			
//			 MergeNode creation
			paletteStack.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddMergeNodeCommand_Label,
							PapyrusMessages.AddMergeNodeCommand_Description,
							MergeNode.class, null));

			entries.add(paletteStack);
			
			// End of control nodes palette stack
			
			
			// Comment creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddCommentCommand_Label,
							PapyrusMessages.AddCommentCommand_Description,
							Comment.class, null));
			// Constraint creation
			entries.add(PapyrusPlugin.creationToolFactory
					.getCombinedTemplateCreationToolEntry(
							PapyrusMessages.AddConstraintCommand_Label,
							PapyrusMessages.AddConstraintCommand_Description,
							Constraint.class, null));			
		} catch (Exception e) {
			PapyrusMessageDialog.display(e.getMessage(), e);
		}

		componentsDrawer.addAll(entries);

		return componentsDrawer;
	}

	/**
	 * Creates the PaletteRoot and adds all palette elements. Use this factory
	 * method to create a new palette for your graphical editor.
	 * 
	 * @return a new PaletteRoot
	 */
	public static DiagramPalette createPalette() {
		DiagramPalette palette = new DiagramPalette(IPapyrusUIConstants.ACTIVITY_DIAGRAM);
		palette.add(createToolsGroup(palette));
		palette.add(createShapesDrawer());

		// Create additionnal menu defined in extensions
		palette.createMenuExtensions();

		return palette;
	}

	/**
	 * Return a FlyoutPreferences instance used to save/load the preferences of
	 * a flyout palette.
	 * 
	 * @return the flyout preferences
	 */
	static FlyoutPreferences createPalettePreferences() {
		return new FlyoutPreferences() {
			private IPreferenceStore getPreferenceStore() {
				return Activator.getDefault().getPreferenceStore();
			}

			public int getDockLocation() {
				return getPreferenceStore().getInt(PALETTE_DOCK_LOCATION);
			}

			public int getPaletteState() {
				return getPreferenceStore().getInt(PALETTE_STATE);
			}

			public int getPaletteWidth() {
				return getPreferenceStore().getInt(PALETTE_SIZE);
			}

			public void setDockLocation(int location) {
				getPreferenceStore().setValue(PALETTE_DOCK_LOCATION, location);
			}

			public void setPaletteState(int state) {
				getPreferenceStore().setValue(PALETTE_STATE, state);
			}

			public void setPaletteWidth(int width) {
				getPreferenceStore().setValue(PALETTE_SIZE, width);
			}
		};
	}

	/**
	 * Creates the tools group.
	 * 
	 * @param palette the palette
	 * 
	 * @return the palette container
	 */
	private static PaletteContainer createToolsGroup(PaletteRoot palette) {
		// PaletteDrawer componentsDrawer = new PaletteDrawer("RelationShips");
		PaletteGroup toolGroup = new PaletteGroup("RelationShips");

		// Add a selection tool to the group
		ToolEntry tool = new PanningSelectionToolEntry();
		toolGroup.add(tool);
		palette.setDefaultEntry(tool);

		// Add a marquee tool to the group
		toolGroup.add(new MarqueeToolEntry());

		// Add a (unnamed) separator to the group
		toolGroup.add(new PaletteSeparator());

		List entries = new ArrayList();
		try {
			PaletteStack paletteStack = null;
			// Add Control Flow
			entries.add(PapyrusPlugin.creationToolFactory
					.getConnectionCreationToolEntry(
							PapyrusMessages.AddControlFlowCommand_Label,
							PapyrusMessages.AddControlFlowCommand_Description,
							ControlFlow.class, null));
			
			// Add Object Flow
			entries.add(PapyrusPlugin.creationToolFactory
					.getConnectionCreationToolEntry(
							PapyrusMessages.AddObjectFlowCommand_Label,
							PapyrusMessages.AddObjectFlowCommand_Description,
							ObjectFlow.class, null));

			///////////////////////////////////////////////////////////////////
			// Begin of tool for Comment and constraint links
			///////////////////////////////////////////////////////////////////
			
			// Add GraphicalLink
			entries.add(PapyrusPlugin.creationToolFactory.getConnectionCreationToolEntry(
					PapyrusMessages.AddGraphicalLinkCommand_Label,
					PapyrusMessages.AddGraphicalLinkCommand_Description,
					GraphicalLink.class,
					null));	

		} catch (Exception e) {
			PapyrusMessageDialog.display(e.getMessage(), e);
		}

		toolGroup.addAll(entries);
		return toolGroup;
	}
}
